using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using Needle.Core.Lifetime;
using Needle.Core.Resolver;
using Needle.Framework;
using Needle.Utils;
using Needle.Utils.Extensions;

namespace Needle.Core
{

    /// <summary>
    /// A default IKernel implementation.
    /// </summary>
    [DebuggerDisplay("Kernel {Name})")]
    public partial class Kernel : NeedleContext, IKernel
    {

        #region constructors
        /// <summary>
        /// Initializes a plain vanilla kernel.
        /// </summary>
        public Kernel() :
            this(new LifetimeManager(), new Needle.Core.Activation.ActivationManager(), new SimpleResolver())
        { }

        /// <summary>
        /// Initializes a kernel with the extra components given.
        /// </summary>
        public Kernel(params IComponent[] components)
        {
            BeginInit();
            foreach (IComponent component in components)
            {
                this.Add(component);
            }
            EndInit();
        }

        #endregion

        #region Initialization
        /// <summary>
        /// Called by the constructor.
        /// </summary>
        public override void BeginInit()
        {
            base.BeginInit();
            IServiceContainer sc = GetService<IServiceContainer>();
            sc.AddService<IKernel>(this);

        }

        /// <summary>
        /// called by the constructor
        /// </summary>
        public override void EndInit()
        {
            foreach (IComponent component in Components)
            {
                IInitializable c = component as IInitializable;
                if (c != null)
                {
                    c.Initialize();
                }
            }
            RegisterInstance<PermanentAttribute, IKernel>(this);
            base.EndInit();
        }

        #endregion
        /// <summary>
        /// /
        /// </summary>
        public void RegisterInstance<TrackingPolicy, TInstance>(TInstance instance)
            where TrackingPolicy : ITrackingPolicy, new()
        {
            RegisterInstance<TrackingPolicy, TInstance>(instance, null);
        }
        /// <summary>
        /// 
        /// </summary>
        public void RegisterInstance<TrackingPolicy, TInstance>(TInstance instance, string name)
            where TrackingPolicy : ITrackingPolicy, new()
        {
            TrackingPolicy trackingPolicy = new TrackingPolicy();
            GetService<ILifetimeManager>().Register(new InstanceId(typeof(TInstance), name), instance, trackingPolicy);
        }

        #region IKernel Members
        /// <summary>
        /// Returns an instance registered for the type, or throws an exception.
        /// </summary>
        public object GetInstance(System.Type t)
        {
            Ensure.NotNull(t, "t");
            return GetInstance(t, null);
        }
        /// <summary>
        /// Returns an instance registered for the type and name given.
        /// </summary>
        public object GetInstance(System.Type t, string name)
        {
            InstanceId id = new InstanceId(t, name);
            return GetInstance(id);
        }
        /// <summary>
        /// Returns a new instance assignable to the type given, or throws an exception.
        /// </summary>
        public T GetInstance<T>()
        {
            return (T)GetInstance(typeof(T), null);
        }

        /// <summary>
        /// Returns an instance registerd for the type and name given.
        /// </summary>
        public T GetInstance<T>(string name)
        {
            Ensure.NotNullOrEmpty(name, "name");
            return (T)GetInstance(typeof(T), name);
        }

        /// <summary>
        /// Returns an instance registerd for the id given.
        /// </summary>
        public object GetInstance(InstanceId id)
        {
            Ensure.NotNull(id, "id");
            IResolver resolver = GetService<IResolver>();
            return resolver.GetInstance(id);
        }

        #endregion

    }
}
